package wxcloud

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

const (
	// 微信云数据库API地址
	databaseAPIURL    = "https://api.weixin.qq.com/tcb/databasequery"
	databaseAddURL    = "https://api.weixin.qq.com/tcb/databaseadd"
	databaseUpdateURL = "https://api.weixin.qq.com/tcb/databaseupdate"
	databaseDeleteURL = "https://api.weixin.qq.com/tcb/databasedelete"
	databaseCountURL  = "https://api.weixin.qq.com/tcb/databasecount"
)

// DatabaseRequest 数据库请求的通用结构
type DatabaseRequest struct {
	Query string `json:"query"` // 数据库查询语句
	Env   string `json:"env"`   // 环境ID
}

// DatabaseQueryResponse 查询响应结构
type DatabaseQueryResponse struct {
	ErrCode int      `json:"errcode"`
	ErrMsg  string   `json:"errmsg"`
	Data    []string `json:"data"`
	Pager   Pager    `json:"pager"`
}

// DatabaseAddResponse 新增响应结构
type DatabaseAddResponse struct {
	ErrCode int      `json:"errcode"`
	ErrMsg  string   `json:"errmsg"`
	IDList  []string `json:"id_list"`
}

// DatabaseUpdateResponse 更新响应结构
type DatabaseUpdateResponse struct {
	ErrCode  int    `json:"errcode"`
	ErrMsg   string `json:"errmsg"`
	Matched  int    `json:"matched"`
	Modified int    `json:"modified"`
}

// DatabaseDeleteResponse 删除响应结构
type DatabaseDeleteResponse struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	Deleted int    `json:"deleted"`
}

// DatabaseCountResponse 计数响应结构
type DatabaseCountResponse struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	Total   int64  `json:"total"`
}

// Pager 分页信息
type Pager struct {
	Offset int `json:"Offset"`
	Limit  int `json:"Limit"`
	Total  int `json:"Total"`
}

// DatabaseQuery 查询数据库记录
func (w *WxCloudClient) DatabaseQuery(ctx context.Context, env, query string) (*DatabaseQueryResponse, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get access token: %w", err)
	}

	req := DatabaseRequest{
		Query: query,
		Env:   env,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", databaseAPIURL, token)

	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var queryResp DatabaseQueryResponse
	if err := json.NewDecoder(resp.Body).Decode(&queryResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if queryResp.ErrCode != 0 {
		return nil, fmt.Errorf("database query error: code=%d, msg=%s", queryResp.ErrCode, queryResp.ErrMsg)
	}

	return &queryResp, nil
}

// DatabaseAdd 新增数据库记录
func (w *WxCloudClient) DatabaseAdd(ctx context.Context, env, query string) ([]string, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get access token: %w", err)
	}

	req := DatabaseRequest{
		Query: query,
		Env:   env,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", databaseAddURL, token)
	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var addResp DatabaseAddResponse
	if err := json.NewDecoder(resp.Body).Decode(&addResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if addResp.ErrCode != 0 {
		return nil, fmt.Errorf("database add error: code=%d, msg=%s", addResp.ErrCode, addResp.ErrMsg)
	}

	return addResp.IDList, nil
}

// DatabaseUpdate 更新数据库记录
func (w *WxCloudClient) DatabaseUpdate(ctx context.Context, env, query string) (int, int, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return 0, 0, fmt.Errorf("failed to get access token: %w", err)
	}

	req := DatabaseRequest{
		Query: query,
		Env:   env,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return 0, 0, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", databaseUpdateURL, token)
	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return 0, 0, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return 0, 0, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var updateResp DatabaseUpdateResponse
	if err := json.NewDecoder(resp.Body).Decode(&updateResp); err != nil {
		return 0, 0, fmt.Errorf("failed to decode response: %w", err)
	}

	if updateResp.ErrCode != 0 {
		return 0, 0, fmt.Errorf("database update error: code=%d, msg=%s", updateResp.ErrCode, updateResp.ErrMsg)
	}

	return updateResp.Matched, updateResp.Modified, nil
}

// DatabaseDelete 删除数据库记录
func (w *WxCloudClient) DatabaseDelete(ctx context.Context, env, query string) (int, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return 0, fmt.Errorf("failed to get access token: %w", err)
	}

	req := DatabaseRequest{
		Query: query,
		Env:   env,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return 0, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", databaseDeleteURL, token)
	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return 0, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return 0, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var deleteResp DatabaseDeleteResponse
	if err := json.NewDecoder(resp.Body).Decode(&deleteResp); err != nil {
		return 0, fmt.Errorf("failed to decode response: %w", err)
	}

	if deleteResp.ErrCode != 0 {
		return 0, fmt.Errorf("database delete error: code=%d, msg=%s", deleteResp.ErrCode, deleteResp.ErrMsg)
	}

	return deleteResp.Deleted, nil
}

// DatabaseCount 统计数据库记录数量
func (w *WxCloudClient) DatabaseCount(ctx context.Context, env, query string) (int64, error) {
	token, err := w.AccessToken(ctx)
	if err != nil {
		return 0, fmt.Errorf("failed to get access token: %w", err)
	}

	req := DatabaseRequest{
		Query: query,
		Env:   env,
	}

	reqBody, err := json.Marshal(req)
	if err != nil {
		return 0, fmt.Errorf("failed to marshal request: %w", err)
	}

	url := fmt.Sprintf("%s?access_token=%s", databaseCountURL, token)
	httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return 0, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")

	resp, err := w.httpClient.Do(httpReq)
	if err != nil {
		return 0, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	var countResp DatabaseCountResponse
	if err := json.NewDecoder(resp.Body).Decode(&countResp); err != nil {
		return 0, fmt.Errorf("failed to decode response: %w", err)
	}

	if countResp.ErrCode != 0 {
		return 0, fmt.Errorf("database count error: code=%d, msg=%s", countResp.ErrCode, countResp.ErrMsg)
	}

	return countResp.Total, nil
}

// BuildQuery 构建查询语句的辅助函数
type QueryBuilder struct {
	collection string
	where      map[string]interface{}
	limit      int
	skip       int
	orderBy    []map[string]interface{}
	fields     []string
}

// NewQueryBuilder 创建查询构建器
func NewQueryBuilder(collection string) *QueryBuilder {
	return &QueryBuilder{
		collection: collection,
		where:      make(map[string]interface{}),
		limit:      100, // 默认限制100条
	}
}

// Where 添加查询条件
func (qb *QueryBuilder) Where(field string, value interface{}) *QueryBuilder {
	qb.where[field] = value
	return qb
}

// Limit 设置查询数量限制
func (qb *QueryBuilder) Limit(limit int) *QueryBuilder {
	qb.limit = limit
	return qb
}

// Skip 设置跳过记录数
func (qb *QueryBuilder) Skip(skip int) *QueryBuilder {
	qb.skip = skip
	return qb
}

// OrderBy 设置排序字段
func (qb *QueryBuilder) OrderBy(field string, direction string) *QueryBuilder {
	if qb.orderBy == nil {
		qb.orderBy = make([]map[string]interface{}, 0)
	}
	qb.orderBy = append(qb.orderBy, map[string]interface{}{
		"field":     field,
		"direction": direction, // "asc" 或 "desc"
	})
	return qb
}

// Fields 设置查询字段
func (qb *QueryBuilder) Fields(fields ...string) *QueryBuilder {
	qb.fields = fields
	return qb
}

// BuildQueryString 构建查询字符串
func (qb *QueryBuilder) BuildQueryString() string {
	query := fmt.Sprintf("db.collection(\"%s\")", qb.collection)

	if len(qb.where) > 0 {
		// 转换 where 条件为 JavaScript 对象格式
		whereStr := buildJSObject(qb.where)
		query = fmt.Sprintf("db.collection(\"%s\").where(%s)", qb.collection, whereStr)
	}

	if qb.skip > 0 {
		query = fmt.Sprintf("%s.skip(%d)", query, qb.skip)
	}

	if qb.limit > 0 {
		query = fmt.Sprintf("%s.limit(%d)", query, qb.limit)
	}

	if len(qb.orderBy) > 0 {
		for _, order := range qb.orderBy {
			query = fmt.Sprintf("%s.orderBy(\"%s\", \"%s\")",
				query, order["field"], order["direction"])
		}
	}

	if len(qb.fields) > 0 {
		fieldsStr := buildJSArray(qb.fields)
		query = fmt.Sprintf("%s.field(%s)", query, fieldsStr)
	}

	query = fmt.Sprintf("%s.get()", query)

	return query
}

// buildJSObject 构建 JavaScript 对象格式的字符串
func buildJSObject(obj map[string]interface{}) string {
	if len(obj) == 0 {
		return "{}"
	}

	var parts []string
	for key, value := range obj {
		var valueStr string
		switch v := value.(type) {
		case string:
			valueStr = fmt.Sprintf("\"%s\"", v)
		case int, int32, int64:
			valueStr = fmt.Sprintf("%d", v)
		case float32, float64:
			valueStr = fmt.Sprintf("%f", v)
		case bool:
			valueStr = fmt.Sprintf("%t", v)
		default:
			// 对于复杂对象，使用 JSON 序列化
			bytes, _ := json.Marshal(v)
			valueStr = string(bytes)
		}
		parts = append(parts, fmt.Sprintf("%s:%s", key, valueStr))
	}

	return "{" + strings.Join(parts, ",") + "}"
}

// buildJSArray 构建 JavaScript 数组格式的字符串
func buildJSArray(arr []string) string {
	if len(arr) == 0 {
		return "[]"
	}

	var parts []string
	for _, item := range arr {
		parts = append(parts, fmt.Sprintf("\"%s\"", item))
	}

	return "[" + strings.Join(parts, ",") + "]"
}

// BuildAddString 构建新增语句
func BuildAddString(collection string, data interface{}) string {
	dataBytes, _ := json.Marshal(data)
	return fmt.Sprintf("db.collection(\"%s\").add({data: %s})", collection, string(dataBytes))
}

// BuildUpdateString 构建更新语句
func BuildUpdateString(collection string, where map[string]interface{}, data interface{}) string {
	whereStr := buildJSObject(where)
	dataBytes, _ := json.Marshal(data)
	return fmt.Sprintf("db.collection(\"%s\").where(%s).update({data: %s})",
		collection, whereStr, string(dataBytes))
}

// BuildDeleteString 构建删除语句
func BuildDeleteString(collection string, where map[string]interface{}) string {
	if len(where) > 0 {
		whereStr := buildJSObject(where)
		return fmt.Sprintf("db.collection(\"%s\").where(%s).remove()", collection, whereStr)
	}
	return fmt.Sprintf("db.collection(\"%s\").remove()", collection)
}

// BuildCountString 构建计数语句
func BuildCountString(collection string, where map[string]interface{}) string {
	if len(where) > 0 {
		whereStr := buildJSObject(where)
		return fmt.Sprintf("db.collection(\"%s\").where(%s).count()", collection, whereStr)
	}
	return fmt.Sprintf("db.collection(\"%s\").count()", collection)
}

// QueryCollectionAllData 查询指定集合的所有数据，固定返回10条记录
func (w *WxCloudClient) QueryCollectionAllData(ctx context.Context, collectionName string) ([]map[string]interface{}, error) {
	// 使用 QueryBuilder 构建查询语句，固定查询10条数据
	queryBuilder := NewQueryBuilder(collectionName)
	queryBuilder.Limit(10) // 固定查询10条数据

	queryString := queryBuilder.BuildQueryString()

	// 执行查询
	resp, err := w.DatabaseQuery(ctx, w.envId, queryString)
	if err != nil {
		return nil, fmt.Errorf("failed to query collection %s: %w", collectionName, err)
	}

	// 解析返回的数据
	var results []map[string]interface{}
	for _, dataStr := range resp.Data {
		var data map[string]interface{}
		if err := json.Unmarshal([]byte(dataStr), &data); err != nil {
			return nil, fmt.Errorf("failed to unmarshal data: %w", err)
		}
		results = append(results, data)
	}

	return results, nil
}
